/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.web.approvalformat.core.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.inspur.edp.cdp.common.utils.json.JsonUtil;
import com.inspur.edp.formserver.viewmodel.GspViewModel;
import com.inspur.edp.lcm.metadata.api.IMetadataContent;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.MetadataHeader;
import com.inspur.edp.lcm.metadata.api.entity.MetadataReference;
import com.inspur.edp.lcm.metadata.common.Utils;
import com.inspur.edp.metadata.businesstype.api.MdBizTypeMappingService;
import com.inspur.edp.metadata.rtcustomization.api.CustomizationService;
import com.inspur.edp.web.approvalformat.api.entity.ApprovalFormatCreateRequestBody;
import com.inspur.edp.web.common.customexception.WebCustomException;
import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import com.inspur.edp.formserver.viewmodel.extendinfo.entity.GspVoExtendInfo;
import com.inspur.edp.formserver.viewmodel.extendinfo.api.GspVoExtendInfoService;
import com.inspur.edp.sgf.api.service.EapiMetadataRtService;
import com.inspur.edp.sgf.api.service.EapiRuntimeDeployment;
import com.inspur.edp.sgf.api.entity.SgMetadata;
import com.inspur.edp.web.common.utility.StringUtility;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 审批单据工具类
 *
 * @author Xu‘fa Wang
 * @date 2020/5/19 20:47
 */
public class ApprovalFormUtil {
    private static final CustomizationService customizationService = SpringBeanUtils.getBean(CustomizationService.class);
    private static final MdBizTypeMappingService mdBizTypeMappingService = SpringBeanUtils.getBean(MdBizTypeMappingService.class);
    private static final ObjectMapper mapper = Utils.getMapper();
    private static final GspVoExtendInfoService gspVoExtendInfoService = SpringBeanUtils.getBean(GspVoExtendInfoService.class);
    private static final EapiMetadataRtService eapiMetadataRtService = SpringBeanUtils.getBean(EapiMetadataRtService.class);
    private static final EapiRuntimeDeployment eapiRuntimeDeployment = SpringBeanUtils.getBean(EapiRuntimeDeployment.class);


    /**
     * 创建根审批单据
     *
     * @param request      审批格式创建请求体
     * @param metadataType 元数据类型
     */
    public static void createRootApprovalForm(ApprovalFormatCreateRequestBody request, String metadataType) {
        //保存元数据到表：GspmdCustomContent
        MetadataHeader header = createHeader(request, metadataType);
        IMetadataContent content = createMetadataContent(request, metadataType);
        GspMetadata metadata = new GspMetadata() {
            {
                this.setHeader(header);
                this.setContent(content);
                //临时添加，为了与运行时定制表单区分
                this.setExtendProperty("APPROVAL");
            }
        };

        customizationService.save(metadata);
        // 保存关联关系到 gspmdbiztypemapping
        createMatadataBizTypeMapping(request, metadataType);
        //部署viewModel和Eapi

        if ("GSPViewModel".equals(metadataType)) {
            //idp类型be暂不使用eapi取数
            if (!StringUtility.isNullOrEmpty(metadata.getHeader().getNameSpace())) {
                //可能部署eapi失败的情况
                if (metadata.getHeader() != null && metadata.getHeader().getCode() != null && metadata.getHeader().getCode().contains("com.inspur.fastdweb")) {
                    return;
                }
                //部署viewModel
                deployViewModel(request, metadata);
                //创建运行时Eapi元数据,注意idp类型
                GspMetadata RtEapiMetadata = eapiMetadataRtService.createRtEapi(metadata);
                //自动保存
                //customizationService.save(RtEapiMetadata);
                //部署Eapi元数据
                eapiRuntimeDeployment.deploy(RtEapiMetadata.getHeader().getId());
                //记录baseUri放置到表单元数据中
                SgMetadata sgMetadata = (SgMetadata) RtEapiMetadata.getContent();
                //"/api/scm/sd/v1.0/kuozhan_ebs"
                String baseUri = sgMetadata.getRouter();

                //更新Eapi元数据id到表单元数据中
                ObjectNode formModule = (ObjectNode) JsonUtil.toJsonNode(request.getFormContent());
                ObjectNode voContent = (ObjectNode) formModule.at("/module/schemas/0");
                voContent.put("eapiId", RtEapiMetadata.getHeader().getId());
                voContent.put("getDataMethod", "byEapi");
                voContent.put("baseUri", baseUri);
                //更新表单元数据
                GspMetadata formMetadata = customizationService.getMetadata(request.getFormId());
                GspMetadata newMetadata = (GspMetadata) formMetadata.clone();
                newMetadata.setContent(new FormMetadataContent() {
                    {
                        this.setId(request.getFormId());
                        this.setContents(formModule);
                    }
                });
                customizationService.save(newMetadata);
            }
        }
    }

    /**
     * 判断元数据对应的(namespace+code+type)是否重复
     *
     * @param request      审批格式创建请求体
     * @param metadataType gsp元数据
     */
    public static void saveCheck(ApprovalFormatCreateRequestBody request, String metadataType) {
        //保存元数据到表：GspmdCustomContent
        MetadataHeader header = createHeader(request, metadataType);
        IMetadataContent content = createMetadataContent(request, metadataType);
        GspMetadata metadata = new GspMetadata() {
            {
                this.setHeader(header);
                this.setContent(content);
                //临时添加，为了与运行时定制表单区分
                this.setExtendProperty("APPROVAL");
            }
        };
        //相同元数据namespace + code + type 重复检测，发生重复会抛出异常
        try {
            customizationService.saveCheck(metadata);
        } catch (Exception e) {
            throw new WebCustomException(ApprovalFormatTranslateUtil.getMessage("uniqueVerificationFailed")
            );
        }
    }

    /**
     * 部署VO,避免重复读取元数据
     *
     * @param request           ApprovalFormatCreateRequestBody
     * @param ViewModelMetadata 视图对象元数据
     */
    public static void deployViewModel(ApprovalFormatCreateRequestBody request, GspMetadata ViewModelMetadata) {
        GspViewModel vo = (GspViewModel) ViewModelMetadata.getContent();
        Date date = new Date();
        GspVoExtendInfo gspVoExtendInfo = new GspVoExtendInfo(ViewModelMetadata.getHeader().getId(), "", vo.getGeneratedConfigID(), null, date, null, date, request.getBeId());
        List<GspVoExtendInfo> gspVoExtendInfoList = new ArrayList<>();
        gspVoExtendInfoList.add(gspVoExtendInfo);
        gspVoExtendInfoService.saveGspVoExtendInfos(gspVoExtendInfoList);
    }

    /**
     * 创建子审批单据
     *
     * @param request      审批格式创建请求体
     * @param metadataType 元数据类型
     */
    public static void createChildApprovalForm(ApprovalFormatCreateRequestBody request, String metadataType) {
        GspMetadata originalMetaData = null;
        switch (metadataType) {
            case "Form":
                originalMetaData = getMetadata(request.getBasicFormId());
                break;
            case "GSPViewModel":
                originalMetaData = getMetadata(request.getBasicVoId());
                break;
            default:
                break;
        }

        if (originalMetaData == null) {
            return;
        }

        //修改Header节点
        //只有Content节点没有Clone
        GspMetadata newMetadata = (GspMetadata) originalMetaData.clone();
        newMetadata.setHeader(createHeader(request, metadataType));
//        //修改元数据extend标志位
//        newMetadata.setExtended(true);
        // 添加扩展属性，唯一标识审批单据
        newMetadata.setExtendProperty("APPROVAL");
        // 修改Content节点
        IMetadataContent metadataContent = createMetadataContent(request, metadataType);
        newMetadata.setContent(metadataContent);

        // 修改Refs节点中Metadata属性
        for (MetadataReference extendMetadataRef : newMetadata.getRefs()) {
            extendMetadataRef.getMetadata().setCode(request.getCode());
            extendMetadataRef.getMetadata().setName(request.getName());
            extendMetadataRef.getMetadata().setId(getNewMetadataId(request, metadataType));
        }

        customizationService.save(newMetadata);

        // 保存关联关系到 gspmdbiztypemapping
        createMatadataBizTypeMapping(request, metadataType);
        if ("GSPViewModel".equals(metadataType)) {
            if (newMetadata.getHeader().getNameSpace() != null && newMetadata.getHeader().getNameSpace() != "") {
                //可能部署eapi失败的情况
                if (newMetadata.getHeader().getCode().indexOf('-') != -1) {
                    return;
                }
                //部署viewModel
                deployViewModel(request, newMetadata);
                //创建运行时Eapi元数据
                GspMetadata RtEapiMetadata = eapiMetadataRtService.createRtEapi(newMetadata);
                //无需save
                //customizationService.save(RtEapiMetadata);
                //部署Eapi元数据
                try {
                    eapiRuntimeDeployment.deploy(RtEapiMetadata.getHeader().getId());
                } catch (Exception e) {
                    Object[] params = {e.getMessage()};
                    throw new WebCustomException(ApprovalFormatTranslateUtil.getMessage("deployEapiError", params));
                }
                //记录baseUri放置到表单元数据中
                SgMetadata sgMetadata = (SgMetadata) RtEapiMetadata.getContent();
                //"/api/scm/sd/v1.0/kuozhan_ebs"
                String baseUri = sgMetadata.getRouter();

                //更新Eapi元数据id到表单元数据中
                ObjectNode formModule = (ObjectNode) JsonUtil.toJsonNode(request.getFormContent());
                ObjectNode voContent = (ObjectNode) formModule.at("/module/schemas/0");
                voContent.put("eapiId", RtEapiMetadata.getHeader().getId());
                voContent.put("getDataMethod", "byEapi");
                voContent.put("baseUri", baseUri);
                //更新表单元数据
                GspMetadata formMetadata = customizationService.getMetadata(request.getFormId());
                GspMetadata metadata = (GspMetadata) formMetadata.clone();
                metadata.setContent(new FormMetadataContent() {
                    {
                        this.setId(request.getFormId());
                        this.setContents(formModule);
                    }
                });
                customizationService.save(newMetadata);
            }
        }

    }

    /**
     * 获取元数据
     *
     * @param metadataId 元数据
     * @return 查询到的元数据
     */
    private static GspMetadata getMetadata(String metadataId) {
        return customizationService.getMetadata(metadataId);
    }

    private static String getNewMetadataId(ApprovalFormatCreateRequestBody requestBody, String metadataType) {
        String metaDataId = null;
        switch (metadataType) {
            case "Form":
                metaDataId = requestBody.getFormId();
                break;
            case "GSPViewModel":
                metaDataId = requestBody.getVoId();
                break;
            default:
                break;
        }
        return metaDataId;
    }

    private static String appendSuffix(String originalString, String metadataType) {
        String metadataSuffix = "_maf";
        String resultString = originalString;
        if (metadataType.equals("GSPViewModel")) {
            resultString = originalString + metadataSuffix;
        }
        return resultString;
    }

    private static MetadataHeader createHeader(ApprovalFormatCreateRequestBody requestBody, String metaDataType) {
        String metaDataId = getNewMetadataId(requestBody, metaDataType);

        MetadataHeader header = new MetadataHeader();
        header.setId(metaDataId);
        //有效避免Eapi的baseUrl重复
        header.setCode(appendSuffix(requestBody.getCode(), metaDataType));
        header.setName(appendSuffix(requestBody.getName(), metaDataType));
        header.setType(metaDataType);
        header.setBizobjectID(requestBody.getBizObjectId());
        header.setNameSpace(requestBody.getNameSpace());
        return header;
    }

    private static IMetadataContent createMetadataContent(ApprovalFormatCreateRequestBody requestBody, String metaDataType) {
        switch (metaDataType) {
            case "Form":
                return new FormMetadataContent() {
                    {
                        this.setId(requestBody.getFormId());
                        //this.setName(requestBody.getName());
                        //this.setCode(requestBody.getCode());
                        //String转换为JsonNode
                        //this.setContents(requestBody.getFormContent());
                        this.setContents(JsonUtil.toJsonNode(requestBody.getFormContent()));

                    }
                };
            case "GSPViewModel":
                try {
                    return mapper.readValue(requestBody.getVoContent(), GspViewModel.class);
                } catch (JsonProcessingException e) {
                    Object[] params = {metaDataType};
                    throw new WebCustomException(ApprovalFormatTranslateUtil.getMessage("createMetadataError", params));
                }
            default:
                return null;
        }
    }

    private static void createMatadataBizTypeMapping(ApprovalFormatCreateRequestBody req, String metaDataType) {
        switch (metaDataType) {
            case "Form":
                mdBizTypeMappingService.save(req.getBillCategoryId(), req.getFormId());
                break;
            case "GSPViewModel":
                mdBizTypeMappingService.save(req.getBillCategoryId(), req.getVoId());
                break;
            default:
                break;
        }
    }

    /**
     * 根据请求信息部署eapi元数据并同步到表单元数据中
     *
     * @param request        ApprovalFormatCreateRequestBody
     * @param rtEapiMetadata 运行时eapi元数据
     */
    private static void DeployEapiMetadataAndSyncToFormMetadata(ApprovalFormatCreateRequestBody request, GspMetadata rtEapiMetadata) {
        eapiRuntimeDeployment.deploy(rtEapiMetadata.getHeader().getId());
        SgMetadata sgMetadata = (SgMetadata) rtEapiMetadata.getContent();
        //"/api/scm/sd/v1.0/kuozhan_ebs"
        String baseUri = sgMetadata.getRouter();
        ObjectNode formModule = (ObjectNode) JsonUtil.toJsonNode(request.getFormContent());
        ObjectNode voContent = (ObjectNode) formModule.at("/module/schemas/0");
        voContent.put("eapiId", rtEapiMetadata.getHeader().getId());
        voContent.put("getDataMethod", "byEapi");
        voContent.put("baseUri", baseUri);
        //更新表单元数据
        GspMetadata formMetadata = customizationService.getMetadata(request.getFormId());
        GspMetadata newMetadata = (GspMetadata) formMetadata.clone();
        newMetadata.setContent(new FormMetadataContent() {
            {
                this.setId(request.getFormId());
                this.setContents(formModule);
            }
        });
        customizationService.save(newMetadata);
    }

    /**
     * 部署设计器上手工创建的VO和Eapi
     *
     * @param request     ApprovalFormatCreateRequestBody
     * @param viewModelId 视图对象编号
     * @param bizEntityId 业务实体编号
     */
    public static void deployManualVOandEapi(ApprovalFormatCreateRequestBody request, String viewModelId, String bizEntityId) {
        GspMetadata voMetadata = customizationService.getMetadata(viewModelId);

        GspMetadata voMetadataCopy = (GspMetadata) voMetadata.clone();
        //重新赋值header里的code和name
        String code = voMetadataCopy.getHeader().getCode();
        String name = voMetadataCopy.getHeader().getName();
        voMetadataCopy.getHeader().setCode(appendSuffix(code, "GSPViewModel"));
        voMetadataCopy.getHeader().setName(appendSuffix(name, "GSPViewModel"));
        voMetadataCopy.setContent(voMetadata.getContent());
        try {
            GspMetadata RtEapiMetadata = eapiMetadataRtService.createRtEapi(voMetadataCopy);
            DeployEapiMetadataAndSyncToFormMetadata(request, RtEapiMetadata);
        } catch (Exception e) {
            throw new WebCustomException(ApprovalFormatTranslateUtil.getMessage("VOHasBeenDeployed"));
        }
    }

    /**
     * 部署VO
     *
     * @param viewModelId 视图对象编号
     * @param bizEntityId 业务实体编号
     */
    private static void deployViewModelByVOIdAndBEId(String viewModelId, String bizEntityId) {
        GspMetadata ViewModelMetadata = customizationService.getMetadata(viewModelId);
        GspViewModel vo = (GspViewModel) ViewModelMetadata.getContent();
        Date date = new Date();
        GspVoExtendInfo gspVoExtendInfo = new GspVoExtendInfo(ViewModelMetadata.getHeader().getId(), "", vo.getGeneratedConfigID(), null, date, null, date, bizEntityId);
        List<GspVoExtendInfo> gspVoExtendInfoList = new ArrayList<>();
        gspVoExtendInfoList.add(gspVoExtendInfo);
        gspVoExtendInfoService.saveGspVoExtendInfos(gspVoExtendInfoList);
    }

}
